/**
 * IO Monad
 */
import fs from 'fs'
import { toUpper } from 'lodash/fp'
const compose = (f: (...args: any) => any, g: (...args: any) => any) => {
  return value => f(g(value))
}

class IO {
  static of (value) {
    return new IO(() => value)
  }

  _value: (...args: any) => any
  constructor (fn) {
    this._value = fn
  }

  map (fn) {
    return new IO(compose(fn, this._value))
  }

  join () {
    // 返回IO函子内的值
    return this._value()
  }

  flatMap (fn) {
    // fn返回的是一个函子，map后会产生函子嵌套，调用join来返回被嵌套的函子，来扁平化嵌套函子
    return this.map(fn).join()
  }
}

let readFile = filename => IO.of(fs.readFileSync(filename, 'utf-8'))
let print = x => IO.of(x).map(x => {
  console.log(x)
  return x
})

/**
 * 当处理值的函数返回的是一个新函子的时候会产生嵌套函子,
 * 此时调用flatMap方法接收这个函数，将被嵌套的函子返回，来扁平化函子
 */

let r = readFile('../../package.json')
          .map(toUpper)
          .flatMap(print)
          .join()
